home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / show / FV21BETA-src.lha / FV21BETA-src / FV.c < prev    next >
C/C++ Source or Header  |  1998-09-17  |  73KB  |  2,547 lines

  1. #include <classes/codec.h>
  2. #include <codecs/jpeg.h>
  3. #include <codecs/picture.h>
  4. #include <cybergraphics/cybergraphics.h>
  5. #include <devices/inputevent.h>
  6. #include <dos/dosasl.h>
  7. #include <exec/execbase.h>
  8. #include <exec/memory.h>
  9. #include <exec/types.h>
  10. #include <graphics/gfxbase.h>
  11. #include <graphics/layers.h>
  12. #include <intuition/intuition.h>
  13. #include <intuition/screens.h>
  14. #include <proto/asl.h>
  15. #include <proto/cybergraphics.h>
  16. #include <proto/dos.h>
  17. #include <proto/exec.h>
  18. #include <proto/graphics.h>
  19. #include <proto/icon.h>
  20. #include <proto/intuition.h>
  21. #include <proto/tower.h>
  22. #include <proto/utility.h>
  23. #include <string.h>
  24. #include <utility/tagitem.h>
  25.  
  26. /*
  27.  
  28.  END
  29. */
  30.  
  31. #define ERROR_INVALID_FILE 21
  32. #define ERROR_EMPTY_FILE 22
  33. #define ERROR_NO_SCREEN 23
  34. #define ERROR_NO_WINDOW 24
  35. #define ERROR_WHILE_DECODING 25
  36. #define ERROR_EARLY_END_OF_FILE 26
  37.  
  38. #define ERROR_END_OF_STREAM 27
  39.  
  40. #define ERROR_UNKNOWN_FILETYPE 28
  41. #define ERROR_NO_SCREENMODE 29
  42.  
  43. /* User wants the next picture while the current one was only partially decoded */
  44. #define USER_NEXTPARTIAL 1
  45. /* User wants the next picture while the current one was fully decoded */
  46. #define USER_NEXTFULL 2
  47. #define USER_EXIT 3
  48.  
  49.  
  50. /* ColorConversion defines:
  51.    PALETTE : Color look-up table, 1 byte per pixel, ranges from 1-8 bits
  52.    FTC     : Fake true color, 1 byte per pixel, ranges from 1-8 bits
  53.    GRAY    : Gray-scale, 1 byte per pixel, ranges from 1-8 bits */
  54.  
  55. #define CC_PALETTE   0
  56. #define CC_FTC       1
  57. #define CC_GRAY      2
  58. #define CC_TRUECOLOR 3
  59. #define CC_UNKNOWN   255
  60.  
  61. /* ColorInput defines:
  62.    PALETTE : Color look-up table, 1 byte per pixel (after P2C), ranges from 1-8 bits
  63.    GRAY    : Gray-scale, 1 byte per pixel (after P2C), ranges from 1-8 bits
  64.    RGB     : True Color, 3 bytes per pixel (after P2C), always 24-bit
  65.    HAM     : Hold-and-modify, 1 byte per pixel (after P2C), 6 or 8 bits
  66.    EHB     : Extra-half-brite, 1 byte per pixel (after P2C), always 6 bits */
  67.  
  68. #define CI_PALETTE 0
  69. #define CI_GRAY    1
  70. #define CI_RGB     2
  71. #define CI_HAM     3
  72. #define CI_EHB     4
  73.  
  74. extern ULONG __stack=8192+4096;
  75.  
  76. /* working switches: FILES,ALL,ORDER,LEAVEMEM,DEBUG,INFO,F1-F10 */
  77.  
  78. char template[]="FILES/M,ALL/S,ORDER/K,DITHER/S,SCALE/S,DELAY/K/N,INFO/K,WAITFORPIC/S,"\
  79.                 "ROM/S,POINTER/S,DEBUG/S,SM=SCREENMODE/K,COMMENT/K,"\
  80.                 "LEAVEMEM/K/N,USECHIP/S,PUBSCREEN/K,GRAY=GREY/S,"\
  81.                 "SLOWSWITCH/S,CAT/K/N,F1/K,F2/K,F3/K,F4/K,F5/K,F6/K,F7/K,F8/K,F9/K,F10/K"
  82.  
  83. #include "FV.hi"
  84.  
  85. ULONG leavemem=1024*4096;
  86. UBYTE *par_info="%n (%xx%yx%d) %c";
  87.  
  88. struct {char **files;
  89.         ULONG all;
  90.         UBYTE *order;
  91.         ULONG dither;
  92.         ULONG scale;
  93.         ULONG *delay;
  94.         UBYTE *info;
  95.         ULONG waitforpic;
  96.         ULONG rom;
  97.         ULONG pointer;
  98.         ULONG debug;
  99.         char *screenmode;
  100.         char *comment;
  101.         ULONG *leavemem;
  102.         ULONG usechip;
  103.         char *pubscreen;
  104.         ULONG gray;
  105.         ULONG slowswitch;
  106.         ULONG *cat;
  107.         char *f1;
  108.         char *f2;
  109.         char *f3;
  110.         char *f4;
  111.         char *f5;
  112.         char *f6;
  113.         char *f7;
  114.         char *f8;
  115.         char *f9;
  116.         char *f10;} arglist={NULL};
  117.  
  118. char scrchoicetemplate[]="NOMW/N,NOMH/N,DEPTH/N,DESCRIPTION";
  119.  
  120. struct ScrChoice {
  121.   ULONG *nomw;
  122.   ULONG *nomh;
  123.   ULONG *depth;
  124.   UBYTE *description;
  125.  
  126.   struct RDArgs *readargs;
  127.   ULONG modeid;    /* if INVALID_ID then this ScrChoice structure is to be ignored */
  128.  
  129.   struct ScrChoice *next;
  130. };
  131.  
  132. struct ScrChoice *firstscrchoice;
  133.  
  134. char buffer[8192];
  135.  
  136. ULONG loadrgb32[3*256+2];
  137.  
  138. /* Structure which is used as a header for a block of data to be displayed now or in
  139.    the future */
  140.  
  141. struct DisplayData {
  142.   struct Node node;
  143.   UWORD row;
  144.   UWORD rowstodec;
  145.   UWORD pad;
  146.  
  147.   struct LineHeader lh[8];
  148. };
  149.  
  150. struct PicType {
  151.   BOOL(*recognisefunc)(struct ScreenNode *);
  152.   LONG(*initfunc)(struct ScreenNode *);
  153.   void(*exitfunc)(struct ScreenNode *);
  154.   LONG __asm(*decodefunc)(register __a0 struct ScreenNode *,register __d0 UWORD,register __a1 UBYTE *);
  155.   char *code;
  156. };
  157.  
  158.  
  159. ULONG __saveds __asm bfillhookfunc(register __a0 struct Hook *,register __a2 APTR,register __a1 APTR);
  160.  
  161. struct Hook bfillhook={0,0,bfillhookfunc,0,0};
  162.  
  163. struct ScrChoice *bestmodeid(struct ScreenNode *);
  164. LONG openscreen(struct ScreenNode *);
  165. void closescreen(struct ScreenNode *);
  166. LONG checkmsg(void);
  167. LONG decodepicture(struct ScreenNode *,struct PicType *);
  168. void displaypicture(struct ScreenNode *,struct DisplayData *);
  169.  
  170. LONG initloader(struct ScreenNode *,ULONG);
  171. LONG doloader(struct ScreenNode *);
  172. void freeloader(struct ScreenNode *);
  173.  
  174. void infotext(struct ScreenNode *);
  175. void makeinfostring(UBYTE *,UBYTE *,UWORD,struct ScreenNode *);
  176. void copypalette(struct ScreenNode *,UBYTE *);
  177. void printfault(LONG,UBYTE *);
  178. struct ScreenNode *freescreennode(struct ScreenNode *);
  179. LONG opennextscreen(struct ScreenNode *,struct ScreenNode *);
  180. ULONG rangerandom(ULONG);
  181.  
  182. extern ULONG __asm RANDOM(register __d0 ULONG);
  183.  
  184. extern void __asm RGBTOFTC(register __a0 void *,register __a1 void *,register __d0 UWORD,register __d1 UWORD,register __d2 UWORD);
  185. extern void __asm SCALERGB(register __a0 void *,register __a1 void *,register __d0 UWORD,register __d1 UWORD);
  186. extern void __asm SCALEGRAY(register __a0 void *,register __a1 void *,register __d0 UWORD,register __d1 UWORD);
  187.  
  188. UBYTE ftctable[3*8]={0,1,0, 1,1,0, 1,1,1, 1,2,1, 2,2,1, 2,2,2, 2,3,2, 3,3,2};
  189.  
  190. BOOL recogniseJPEG(struct ScreenNode *);
  191. LONG initJPEG(struct ScreenNode *);
  192. void exitJPEG(struct ScreenNode *);
  193. LONG __asm decodeJPEG(register __a0 struct ScreenNode *,register __d0 UWORD,register __a1 UBYTE *);
  194.  
  195. BOOL recogniseGIF(struct ScreenNode *);
  196. LONG initGIF(struct ScreenNode *);
  197. void exitGIF(struct ScreenNode *);
  198. LONG __asm extern DECODEGIF(register __a0 struct ScreenNode *,register __d0 UWORD,register __a1 UBYTE *);
  199.  
  200. struct PicType pictypes[]={recogniseJPEG,initJPEG,exitJPEG,decodeJPEG,"JPEG",
  201.                            recogniseGIF,initGIF,exitGIF,DECODEGIF,"GIF",
  202.                            0,0,0,0,0};
  203.  
  204. struct Library *UtilityBase;
  205. struct Library *CyberGfxBase;
  206. struct Library *TowerBase;
  207. extern struct ExecBase *SysBase;
  208. struct GfxBase *GfxBase;
  209.  
  210. static ULONG BitMapDepth(struct BitMap *);
  211. static void DeleteBitMap(struct BitMap *);
  212. struct BitMap *CreateBitMap(LONG,LONG,LONG);
  213.  
  214. struct ScreenNode *activescreen=0;
  215.  
  216. void InitList(struct List *);
  217. void debugreq(UBYTE *);
  218.  
  219. struct List snlist;
  220.  
  221. ULONG rndseed;
  222.  
  223. struct FileNode {
  224.   struct MinNode minnode;
  225.   UBYTE name[1]; /* name followed by comment */
  226. };
  227.  
  228. struct Screen *wbscr;
  229. UWORD wbfontysize=0;
  230.  
  231. ULONG main() {
  232.   struct ScrChoice *sc;
  233.   struct ScreenNode *sn;
  234.   struct RDArgs *readarg;
  235.   char **curfile;
  236.   ULONG errorcode,filecnt;
  237.   struct PicType *pictype;
  238.   UBYTE picdecoded;
  239.   UBYTE __aligned extendedap[sizeof(struct AnchorPath)+1024]={0};
  240.   struct AnchorPath *ap;
  241.   void *filepool;
  242.   void *scrchoicepool;
  243.   struct MinList filelist;
  244.   struct DateStamp ds;
  245.  
  246.   ap=(struct AnchorPath *)extendedap;
  247.   ap->ap_Strlen=1020;
  248.  
  249.   InitList(&snlist);
  250.   InitList((struct List *)&filelist);
  251.  
  252.   errorcode=RETURN_FAIL;
  253.   if((DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37))!=0) {
  254.     if((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37))!=0) {
  255.       if((AslBase=OpenLibrary("asl.library",36))!=0) {
  256.         if((IconBase=OpenLibrary("icon.library",37))!=0) {
  257.           if((UtilityBase=OpenLibrary("utility.library",37))!=0) {
  258.             if((GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37))!=0) {
  259.               TowerBase=OpenLibrary("tower.library",1);
  260.               CyberGfxBase=OpenLibrary("cybergraphics.library",40);
  261.  
  262.               if((wbscr=LockPubScreen("Workbench"))!=0) {
  263.                 /* Creating a nice randomseed */
  264.  
  265.                 DateStamp(&ds);
  266.                 if((rndseed=(((ULONG)&filelist)^(ds.ds_Days<<16)^(ds.ds_Minute<<8)^(ds.ds_Tick>>1)) & 0x3fffffff)==0) {
  267.                   rndseed=0x40000000;
  268.                 }
  269.  
  270.                 PutStr("FastView 2.1 (18 November 1996) - Programmed by John Hendrikx\n");
  271.  
  272.                 if((readarg=ReadArgs(template,(LONG *)&arglist,0))!=0) {
  273.  
  274.                   /* Now override default values for any parameters passed in */
  275.  
  276.                   if(arglist.leavemem!=0) {
  277.                     leavemem=*arglist.leavemem;
  278.                   }
  279.                   if(arglist.info!=0) {
  280.                     if(*arglist.info!=0) {
  281.                       par_info=arglist.info;
  282.                     }
  283.                   }
  284.  
  285.                   if(arglist.info!=0) {
  286.                     wbfontysize=wbscr->Font->ta_YSize;
  287.                   }
  288.  
  289.                   if((scrchoicepool=CreatePool(0,512,512))!=0) {
  290.                     {
  291.                       BPTR fh;
  292.                       UBYTE *linebuf;
  293.  
  294.                       if((linebuf=AllocVec(1024,0))!=0) {
  295.                         if((fh=Open("PROGDIR:fvmodes",MODE_OLDFILE))!=0) {
  296.                           LONG line=1;
  297.                           struct ScrChoice *sc;
  298.  
  299.                           while(FGets(fh,linebuf,1020)!=0) {
  300.                             if(*linebuf!='*' && *linebuf!=';' && *linebuf!=0 && *linebuf!='#') {
  301.                               if((sc=AllocPooled(scrchoicepool,sizeof(struct ScrChoice)))!=0) {
  302.                                 if((sc->readargs=AllocDosObject(DOS_RDARGS,0))!=0) {
  303.                                   sc->readargs->RDA_Source.CS_Buffer=linebuf;
  304.                                   sc->readargs->RDA_Source.CS_Length=strlen(linebuf);
  305.                                   sc->readargs->RDA_Flags=RDAF_NOPROMPT;
  306.  
  307.                                   if(ReadArgs(scrchoicetemplate,(LONG *)sc,sc->readargs)!=0) {
  308.                                     sc->next=firstscrchoice;
  309.                                     firstscrchoice=sc;
  310.  
  311.                                     sc->modeid=BestCModeIDTags(CYBRBIDTG_Depth,*sc->depth,CYBRBIDTG_NominalWidth,*sc->nomw,CYBRBIDTG_NominalHeight,*sc->nomh);
  312.  
  313.                                     if(sc->modeid==INVALID_ID) {
  314.                                       VPrintf("fvmodes: unable to find a suitable screenmode for line %ld.",&line);
  315.                                     }
  316.  
  317.                                     if(arglist.debug!=0) {
  318.                                       VPrintf("(DEBUG) At line %2ld: ",&line);
  319.                                       VPrintf("NOMW=%4ld ",sc->nomw);
  320.                                       VPrintf("NOMH=%4ld ",sc->nomh);
  321.                                       VPrintf("DEPTH=%2ld ",sc->depth);
  322.                                       VPrintf("MODEID=$%08lx ",&sc->modeid);
  323.                                       VPrintf("DESCRIPTION=%s\n",&sc->description);
  324.                                     }
  325.                                   }
  326.                                   else {
  327.                                     // FreePooled(scrchoicepool,sc,sizeof(struct ScrChoice));
  328.                                     VPrintf("fvmodes: error in line %ld.\n",&line);
  329.                                     break;
  330.                                   }
  331.                                 }
  332.                               }
  333.                             }
  334.                             else if(*linebuf=='#') {
  335.                               break;
  336.                             }
  337.                             line++;
  338.                           }
  339.                           Close(fh);
  340.                         }
  341.                         else {
  342.                           PutStr("fvmodes: file not found.\n");
  343.                         }
  344.                         FreeVec(linebuf);
  345.                       }
  346.                       else {
  347.                         PutStr("fvmodes: not enough memory for linebuffer.\n");
  348.                       }
  349.                     }
  350.  
  351.                     if((curfile=arglist.files)!=0) {
  352.  
  353.                       if((filepool=CreatePool(0,4096,4096))!=0) {
  354.  
  355.                         filecnt=0;
  356.  
  357.                         while(*curfile!=0) {
  358.                           struct FileNode *fn;
  359.  
  360.                           errorcode=MatchFirst(*curfile,ap);
  361.                           if(errorcode!=0 && errorcode!=ERROR_NO_MORE_ENTRIES) {
  362.                             printfault(errorcode,*curfile);
  363.                             break;
  364.                           }
  365.  
  366.                           do {
  367.                             if(ap->ap_Info.fib_EntryType>=0) {
  368.                               if((ap->ap_Flags & APF_DIDDIR)==0 && arglist.all!=0) {
  369.                                 ap->ap_Flags|=APF_DODIR;
  370.                               }
  371.                               else {
  372.                                 ap->ap_Flags&=~APF_DIDDIR;
  373.                               }
  374.                             }
  375.                             else {
  376.                               UBYTE pass=0;
  377.  
  378.                               if(arglist.comment!=0) {
  379.                                 UBYTE space[80];
  380.                                 char *str;
  381.                                 char *str2;
  382.  
  383.                                 str=arglist.comment;
  384.  
  385.                                 for(;;) {
  386.                                   str2=str;
  387.  
  388.                                   while(*str!=0 && *str!=',') {
  389.                                     str++;
  390.                                   }
  391.                                   strncpy(&space[0],str2,str-str2);
  392.                                   space[str-str2]=0;
  393.  
  394.                                   if(strstr(&ap->ap_Info.fib_Comment[0],&space[0])==0) {
  395.                                     pass=1;
  396.                                     break;
  397.                                   }
  398.  
  399.                                   if(*str++==0) {
  400.                                     break;
  401.                                   }
  402.                                 }
  403.                               }
  404.  
  405.                               if(pass==0) {
  406.                                 filecnt++;
  407.  
  408.                                 if((fn=AllocPooled(filepool,sizeof(struct FileNode)+strlen(&ap->ap_Buf[0])+1+strlen(&ap->ap_Info.fib_Comment[0])+1))!=0) {
  409.                                   strcpy(fn->name,&ap->ap_Buf[0]);
  410.                                   strcpy(&fn->name[strlen(&ap->ap_Buf[0])+1],&ap->ap_Info.fib_Comment[0]);
  411.  
  412.                                   if(arglist.order!=0) {
  413.                                     struct FileNode *orderfn=(struct FileNode *)filelist.mlh_Head;
  414.                                     struct FileNode *next;
  415.                                     struct FileNode *prev;
  416.                                     WORD cnt;
  417.                                     ULONG rndval,rndcnt=0;
  418.  
  419.                                     prev=orderfn;
  420.  
  421.                                     switch(*arglist.order & 0xDF) {
  422.                                       case 'A':
  423.                                         for(;;) {
  424.                                           cnt=32;
  425.                                           next=(struct FileNode *)orderfn->minnode.mln_Succ;
  426.  
  427.                                           while(next->minnode.mln_Succ!=0 && cnt--!=0) {
  428.                                             next=(struct FileNode *)next->minnode.mln_Succ;
  429.                                           }
  430.  
  431.                                           if(next->minnode.mln_Succ==0) {
  432.                                             break;
  433.                                           }
  434.  
  435.                                           if(Stricmp(FilePart(&orderfn->name[0]),FilePart(&fn->name[0]))>=0) {
  436.                                             orderfn=prev;
  437.                                             break;
  438.                                           }
  439.  
  440.                                           prev=orderfn;
  441.                                           orderfn=next;
  442.                                         }
  443.  
  444.                                         while(orderfn->minnode.mln_Succ!=0 && Stricmp(FilePart(&orderfn->name[0]),FilePart(&fn->name[0]))<0) {
  445.                                           orderfn=(struct FileNode *)orderfn->minnode.mln_Succ;
  446.                                         }
  447.  
  448.                                         Insert((struct List *)&filelist,(struct Node *)&fn->minnode,(struct Node *)orderfn->minnode.mln_Pred);
  449.                                         break;
  450.                                       case 'P':
  451.                                         while(orderfn->minnode.mln_Succ!=0 && Stricmp(&orderfn->name[0],&fn->name[0])<0) {
  452.                                           orderfn=(struct FileNode *)orderfn->minnode.mln_Succ;
  453.                                         }
  454.                                         Insert((struct List *)&filelist,(struct Node *)&fn->minnode,(struct Node *)orderfn->minnode.mln_Pred);
  455.                                         break;
  456.                                       default:
  457.                                         rndval=rangerandom(filecnt);
  458.                                         while(orderfn->minnode.mln_Succ!=0 && rndcnt++<rndval) {
  459.                                           orderfn=(struct FileNode *)orderfn->minnode.mln_Succ;
  460.                                         }
  461.                                         Insert((struct List *)&filelist,(struct Node *)&fn->minnode,(struct Node *)orderfn->minnode.mln_Pred);
  462.                                         break;
  463.                                     }
  464.                                   }
  465.                                   else {
  466.                                     AddTail((struct List *)&filelist,(struct Node *)&fn->minnode);
  467.                                   }
  468.                                 }
  469.                                 else {
  470.                                   errorcode=ERROR_NO_FREE_STORE;
  471.                                   break;
  472.                                 }
  473.                               }
  474.                             }
  475.                           } while((errorcode=MatchNext(ap))==0);
  476.  
  477.                           MatchEnd(ap);
  478.  
  479.                           if(errorcode!=ERROR_NO_MORE_ENTRIES) {
  480.                             break;
  481.                           }
  482.  
  483.                           curfile++;
  484.                         }
  485.  
  486.                         if(errorcode==ERROR_NO_MORE_ENTRIES && filecnt!=0) {
  487.                           struct FileNode *fn=(struct FileNode *)filelist.mlh_Head;
  488.  
  489.                           while(fn->minnode.mln_Succ!=0) {
  490.                             picdecoded=FALSE;
  491.  
  492.                             if((sn=AllocVec(sizeof(struct ScreenNode),MEMF_PUBLIC|MEMF_CLEAR))!=0) {
  493.                               AddTail(&snlist,&sn->node);
  494.                               InitList(&sn->displaydata);
  495.  
  496.                               sn->fn=fn;
  497.  
  498.                               PutStr(&fn->name[0]);
  499.                               PutStr("\n");
  500.                               if((sn->fh=Open(&fn->name[0],MODE_OLDFILE))!=0) {
  501.                                 pictype=pictypes;
  502.                                 while(pictype->recognisefunc!=0) {
  503.                                   if(pictype->recognisefunc(sn)==TRUE) {
  504.                                     break;
  505.                                   }
  506.                                   Seek(sn->fh,0,OFFSET_BEGINNING);
  507.                                   pictype++;
  508.                                 }
  509.  
  510.                                 if(pictype->recognisefunc!=0) {
  511.  
  512.                                   if((errorcode=pictype->initfunc(sn))==0) {
  513.                                     if(arglist.debug!=0) {
  514.                                       ULONG arg[3];
  515.  
  516.                                       arg[0]=sn->width;
  517.                                       arg[1]=sn->height;
  518.                                       arg[2]=sn->depth;
  519.  
  520.                                       VPrintf("(DEBUG) Pic Info  : %ldx%ldx%ld\n",&arg);
  521.                                     }
  522.  
  523.                                     sn->renderw=sn->width;
  524.                                     sn->renderh=sn->height;
  525.  
  526.                                     if((sc=bestmodeid(sn))!=0) {
  527.                                       sn->scrchoice=sc;
  528.                                       sn->modeid=sc->modeid;
  529. /*                                      if(sn->halvewidth==FALSE) {
  530.                                         sn->renderw=sn->width;
  531.                                       }
  532.                                       else {
  533.                                         sn->renderw=(sn->width+1)>>1;
  534.                                       }
  535.                                       sn->renderh=sn->height; */
  536.  
  537. /*                                      if(sn->rerender==FALSE) {
  538.                                         sn->renderd=sn->depth;
  539.                                         if(sn->direct==TRUE) {
  540.                                           if(sn->ham==TRUE) {
  541.                                             sn->displayid|=HAM_KEY;
  542.                                           }
  543.                                           else {
  544.                                             sn->displayid|=EXTRAHALFBRITE_KEY;
  545.                                           }
  546.                                         }
  547.                                       }
  548.                                       else {
  549.                                         sn->renderd=8;
  550.                                         if(sn->gray==TRUE) {
  551.                                           if(sn->deep==FALSE) {
  552.                                             sn->renderd=4;
  553.                                           }
  554.                                         }
  555.                                         else {
  556.                                           sn->displayid|=HAM_KEY;
  557.                                           if(sn->deep==FALSE) {
  558.                                             sn->renderd=6;
  559.                                           }
  560.                                         }
  561.                                       } */
  562.  
  563.                                       if(arglist.debug!=0) {
  564.                                         if(sn->colorinput==CI_PALETTE) {
  565.                                           PutStr("(DEBUG) ColorIn   : Color look-up table\n");
  566.                                         }
  567.                                         else if(sn->colorinput==CI_GRAY) {
  568.                                           PutStr("(DEBUG) ColorIn   : Gray\n");
  569.                                         }
  570.                                         else if(sn->colorinput==CI_RGB) {
  571.                                           PutStr("(DEBUG) ColorIn   : 24-bit RGB\n");
  572.                                         }
  573.                                         else if(sn->colorinput==CI_HAM) {
  574.                                           PutStr("(DEBUG) ColorIn   : HAM\n");
  575.                                         }
  576.  
  577.                                         if(sn->colorconversion==CC_FTC) {
  578.                                           PutStr("(DEBUG) ColorOut  : Fake TrueColor\n");
  579.                                         }
  580.                                         else if(sn->colorconversion==CC_PALETTE) {
  581.                                           PutStr("(DEBUG) ColorOut  : Color look-up table\n");
  582.                                         }
  583.                                         else if(sn->colorconversion==CC_GRAY) {
  584.                                           PutStr("(DEBUG) ColorOut  : Gray\n");
  585.                                         }
  586.                                         else if(sn->colorconversion==CC_TRUECOLOR) {
  587.                                           PutStr("(DEBUG) ColorOut  : TrueColor\n");
  588.                                         }
  589.                                         else if(sn->colorconversion==CC_UNKNOWN) {
  590.                                           PutStr("(DEBUG) ColorOut  : Unknown\n");
  591.                                         }
  592.                                       }
  593.  
  594.                                       sn->outputline=0;
  595.                                       errorcode=decodepicture(sn,pictype);
  596.  
  597.                                       picdecoded=TRUE;
  598.  
  599.                                     }
  600.                                     else {
  601.                                       errorcode=ERROR_NO_SCREENMODE;
  602.                                     }
  603.                                   }
  604.  
  605.                                   pictype->exitfunc(sn);
  606.  
  607.                                 }
  608.                                 else {
  609.                                   errorcode=ERROR_UNKNOWN_FILETYPE;
  610.                                 }
  611.  
  612.                                 freeloader(sn);          /* *always* save to call */
  613.  
  614.                                 if(sn->fh!=0) {
  615.                                   Close(sn->fh);
  616.                                   sn->fh=0;
  617.                                 }
  618.                               }
  619.                               else {
  620.                                 errorcode=IoErr();
  621.                               }
  622.  
  623.                             }
  624.                             else {
  625.                               errorcode=ERROR_NO_FREE_STORE;
  626.                             }
  627.  
  628.                             if(errorcode==USER_EXIT) {
  629.                               break;
  630.                             }
  631.                             if(errorcode==USER_NEXTPARTIAL || picdecoded==FALSE) {
  632.                               /* this "error" can only be returned by decodepicture when the
  633.                                  user pressed the LMB while the currently *visible* picture was
  634.                                  the one being decoded */
  635.  
  636.                               freescreennode(sn);
  637.                             }
  638.                             if(errorcode!=0 && errorcode!=USER_NEXTPARTIAL) {
  639.                               printfault(errorcode,&fn->name[0]);
  640.                             }
  641.  
  642.                             errorcode=0;
  643.                             fn=(struct FileNode *)fn->minnode.mln_Succ;
  644.                           }
  645.  
  646.                           if(errorcode==0 && activescreen!=0) {
  647.                             while((errorcode=checkmsg())==0) {
  648.                               WaitPort(activescreen->window->UserPort);
  649.                             }
  650.                           }
  651.  
  652.                           while(snlist.lh_Head->ln_Succ!=0) {
  653.                             freescreennode((struct ScreenNode *)snlist.lh_Head);
  654.                           }
  655.  
  656.                         }
  657.  
  658.                         DeletePool(filepool);
  659.                       }
  660.                       else {
  661.                         PutStr("Couldn't allocate a memory pool\n");
  662.                       }
  663.                     }
  664.                     else {
  665.                       PutStr("We really should put up a file-requester now\n");
  666.                     }
  667.  
  668.                     {
  669.                       struct ScrChoice *sc;
  670.  
  671.                       sc=firstscrchoice;
  672.                       while(sc!=0) {
  673.                         FreeArgs(sc->readargs);
  674.                         FreeDosObject(DOS_RDARGS,sc->readargs);
  675.                         sc=sc->next;
  676.                       }
  677.                     }
  678.  
  679.                     DeletePool(scrchoicepool);
  680.                   }
  681.  
  682.                   errorcode=0;
  683.                   FreeArgs(readarg);
  684.                 }
  685.  
  686.                 UnlockPubScreen(0,wbscr);
  687.               }
  688.               else {
  689.                 PutStr("Couldn't open Workbench screen\n");
  690.               }
  691.  
  692.               if(TowerBase!=0) {
  693.                 CloseLibrary(TowerBase);
  694.               }
  695.               if(CyberGfxBase!=0) {
  696.                 CloseLibrary(CyberGfxBase);
  697.               }
  698.  
  699.               CloseLibrary((struct Library *)GfxBase);
  700.             }
  701.             else {
  702.               PutStr("Couldn't open graphics.library V37\n");
  703.             }
  704.           }
  705.           else {
  706.             PutStr("Couldn't open utility.library V37\n");
  707.           }
  708.           CloseLibrary((struct Library *)IconBase);
  709.         }
  710.         else {
  711.           PutStr("Couldn't open icon.library V37\n");
  712.         }
  713.         CloseLibrary((struct Library *)AslBase);
  714.       }
  715.       else {
  716.         PutStr("Couldn't open asl.library V36\n");
  717.       }
  718.       CloseLibrary((struct Library *)IntuitionBase);
  719.     }
  720.     else {
  721.       PutStr("Couldn't open intuition.library V37\n");
  722.     }
  723.  
  724.     CloseLibrary((struct Library *)DOSBase);
  725.   }
  726.   return(errorcode);
  727. }
  728.  
  729.  
  730.  
  731. ULONG rangerandom(ULONG range) {
  732.   rndseed=RANDOM(rndseed);
  733.   return(rndseed%range);
  734. }
  735.  
  736.  
  737. /* size must be at least 4 bytes or more */
  738.  
  739. void makeinfostring(UBYTE *str,UBYTE *info,UWORD size,struct ScreenNode *sn) {
  740.   UWORD len,n;
  741.   UBYTE *num;
  742.   UBYTE numspace[12];
  743.   UBYTE procent[]="%";
  744.   UBYTE c;
  745.   struct FileInfoBlock *fib;
  746.  
  747.   if((fib=AllocVec(sizeof(struct FileInfoBlock),0))!=0) {
  748.     size-=2;
  749.  
  750.     len=strlen(info);
  751.  
  752.     for(n=0;n<len;n++) {
  753.       if(*info=='%') {
  754.         info++;
  755.         c=*info++;
  756.  
  757.         if(c=='x') {
  758.           num=&numspace[0];
  759.           stci_d(num,sn->width);
  760.         }
  761.         else if(c=='y') {
  762.           num=&numspace[0];
  763.           stci_d(num,sn->height);
  764.         }
  765.         else if(c=='d') {
  766.           num=&numspace[0];
  767.           stci_d(num,sn->depth);
  768.         }
  769.         else if(c=='c') {
  770.           BPTR lock;
  771.  
  772.           if((lock=Lock(&sn->fn->name[0],SHARED_LOCK))!=0) {
  773.             if(Examine(lock,fib)!=0) {
  774.               num=&fib->fib_Comment[0];
  775.             }
  776.             else {
  777.               num=&procent[1];
  778.             }
  779.             UnLock(lock);
  780.           }
  781.           else {
  782.             num=&procent[1];
  783.           }
  784.         }
  785.         else if(c=='n') {
  786.           num=FilePart(sn->fn->name);
  787.         }
  788.         else if(c=='N') {
  789.           num=sn->fn->name;
  790.         }
  791.         else {
  792.           num=procent;
  793.         }
  794.  
  795.         while(size-->0 && *num!=0) {
  796.           *str++=*num++;
  797.         }
  798.       }
  799.       else {
  800.         *str++=*info++;
  801.         size--;
  802.       }
  803.       if(size<=0) {
  804.         break;
  805.       }
  806.     }
  807.     FreeVec(fib);
  808.   }
  809.  
  810.   *str=0;
  811. }
  812.  
  813.  
  814.  
  815.  
  816.  
  817. LONG checkmsg() {
  818.   struct IntuiMessage *msg;
  819.   ULONG class;
  820.   UWORD code,qualifier;
  821.   LONG errorcode;
  822.   UWORD action;
  823.  
  824.   /* This routine should only pass through an error code or user choice to the
  825.      routines below when this routine absolutely has too! */
  826.  
  827.   if(activescreen==0) {
  828.     if((errorcode=opennextscreen((struct ScreenNode *)snlist.lh_Head,0))!=0) {
  829.  
  830.       /* this usually returns USER_NEXTPARTIAL */
  831.  
  832.       return(errorcode);
  833.     }
  834.   }
  835.  
  836.   while((msg=(struct IntuiMessage *)GetMsg(activescreen->window->UserPort))!=0) {
  837.  
  838.     class=msg->Class;
  839.     code=msg->Code;
  840.     qualifier=msg->Qualifier;
  841.  
  842.     ReplyMsg((struct Message *)msg);
  843.  
  844.     action=0;
  845.  
  846.     if(class==IDCMP_MOUSEBUTTONS) {
  847.       if(code==IECODE_LBUTTON) {
  848.         action=IECODE_LBUTTON;
  849.       }
  850.       else if(code==IECODE_RBUTTON) {
  851.         action=IECODE_RBUTTON;
  852.       }
  853.     }
  854.     else if(class==IDCMP_RAWKEY) {
  855.       if(code==64 || code==68 || code==67) {
  856.         /* Space, Return and Enter */
  857.         action=IECODE_LBUTTON;
  858.       }
  859.       else if(code==70 && (qualifier & IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT)!=0) {
  860.         /* Shift + Del */
  861.  
  862.         if(activescreen->fh!=0) {
  863.           Close(activescreen->fh);
  864.           activescreen->fh=0;
  865.         }
  866.  
  867.         if((errorcode=DeleteFile(&activescreen->fn->name[0]))==0) {
  868.           printfault(IoErr(),&activescreen->fn->name[0]);
  869.         }
  870.         action=IECODE_LBUTTON;
  871.       }
  872.       else if(code==69) {
  873.         /* Escape */
  874.         action=IECODE_RBUTTON;
  875.       }
  876.       else if(code>=80 && code<=89) {
  877.         /* Function key pressed */
  878.         char **a;
  879.  
  880.         code-=80;
  881.  
  882.         a=&arglist.f1;
  883.         a+=code;
  884.  
  885.         if(*a!=0) {
  886.           UBYTE str[512];
  887.  
  888.           makeinfostring(str,*a,512,activescreen);
  889.  
  890.           if(activescreen->fh!=0) {
  891.             Close(activescreen->fh);
  892.             activescreen->fh=0;
  893.           }
  894.  
  895.           Execute(str,0,Output());
  896.  
  897.           infotext(activescreen);
  898.           // action=IECODE_LBUTTON;
  899.         }
  900.       }
  901.       else {
  902.         /* Handle scrolling */
  903.         WORD xs=0,ys=0;
  904.  
  905.         if(code==79 || code==45) {
  906.           /* Left or NUM Left */
  907.           xs=16;
  908.         }
  909.         else if(code==78 || code==47) {
  910.           /* Right or NUM Right */
  911.           xs=-16;
  912.         }
  913.         else if(code==76 || code==62) {
  914.           /* Up or NUM Up */
  915.           ys=16;
  916.         }
  917.         else if(code==77 || code==30) {
  918.           /* Down or NUM Down */
  919.           ys=-16;
  920.         }
  921.         else if(code==29) {
  922.           /* NUM 1 */
  923.           xs=16;
  924.           ys=-16;
  925.         }
  926.         else if(code==31) {
  927.           /* NUM 3 */
  928.           xs=-16;
  929.           ys=-16;
  930.         }
  931.         else if(code==61) {
  932.           /* NUM 7 */
  933.           xs=16;
  934.           ys=16;
  935.         }
  936.         else if(code==63) {
  937.           /* NUM 9 */
  938.           xs=-16;
  939.           ys=16;
  940.         }
  941.         if(xs!=0 || ys!=0) {
  942.           qualifier&=0x33;  /* Both alt en shift keys */
  943.           if((qualifier & IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT)!=0) {
  944.             xs<<=4;
  945.             ys<<=4;
  946.           }
  947.           else if((qualifier & IEQUALIFIER_LALT+IEQUALIFIER_RALT)!=0) {
  948.             xs>>=4;
  949.             ys>>=4;
  950.           }
  951.           if(activescreen->screen->TopEdge+ys>0) {
  952.             ys=-activescreen->screen->TopEdge;
  953.           }
  954.      //     MoveScreen(activescreen->screen,xs,ys);
  955.           ScreenPosition(activescreen->screen,SPOS_RELATIVE,xs,ys,0,0);
  956.         }
  957.       }
  958.     }
  959.  
  960.     if(action==IECODE_LBUTTON) {
  961.       if(activescreen->node.ln_Succ->ln_Succ==0) {
  962.         /* There is no next screen!! */
  963.  
  964.         closescreen(activescreen);
  965.  
  966.         activescreen=0;
  967.  
  968.         return(USER_NEXTPARTIAL);
  969.       }
  970.  
  971.       /* There is a next screen!  Open that one! */
  972.  
  973.       if((errorcode=opennextscreen((struct ScreenNode *)activescreen->node.ln_Succ,activescreen))!=0) {
  974.         /* this usually returns USER_NEXTPARTIAL */
  975.         activescreen=0;
  976.  
  977.         return(errorcode);
  978.       }
  979.  
  980.       /* next screen was opened succesfully, and previous screen was closed.
  981.          No need to tell the decoder what happened, just let it continue :-) */
  982.     }
  983.     else if(action==IECODE_RBUTTON) {
  984.       return(USER_EXIT);
  985.     }
  986.   }
  987.  
  988.   /* Nothing important enough happened to let the decoding loop worry about */
  989.  
  990.   return(0);
  991. }
  992.  
  993.  
  994.  
  995. void debugreq(UBYTE *text) {
  996.   struct EasyStruct es;
  997.  
  998.   es.es_StructSize=sizeof(struct EasyStruct);
  999.   es.es_Flags=0;
  1000.   es.es_Title="FastView Debug requester";
  1001.   es.es_TextFormat=text;
  1002.   es.es_GadgetFormat="Ok";
  1003.  
  1004.   EasyRequestArgs(0,&es,0,0);
  1005. }
  1006.  
  1007.  
  1008.  
  1009. /* sn should be the first or second screennode in the list.  cursn should be zero or
  1010.    be the first screennode in the list.  If cursn is non-zero then this routine will always
  1011.    close, delink & free this screennode! */
  1012.  
  1013. LONG opennextscreen(struct ScreenNode *sn,struct ScreenNode *cursn) {
  1014.   LONG errorcode;
  1015.   UWORD divx,divy;
  1016.  
  1017.   divx=*sn->scrchoice->nomw/sn->renderw;
  1018.   divy=*sn->scrchoice->nomh/sn->renderh;
  1019.  
  1020.   if(divx>divy) {
  1021.     divx=divy;
  1022.   }
  1023.  
  1024.   if(divx>1) {
  1025.     if(divx>4) {
  1026.       divx=4;
  1027.     }
  1028.     sn->renderw*=divx;
  1029.     sn->renderh*=divx;
  1030.   }
  1031.  
  1032.   while((errorcode=openscreen(sn))!=0) {
  1033.     closescreen(sn);
  1034.  
  1035.     if(cursn!=0) {
  1036.       freescreennode(cursn);
  1037.  
  1038.       cursn=0;
  1039.       continue;
  1040.     }
  1041.  
  1042.     if(sn->renderw>320 && sn->renderh>200) {
  1043.       /* inaccurate scaling to 3/4's */
  1044.       sn->renderw=((((ULONG)sn->renderw)<<1)+sn->renderw)>>2;
  1045.       sn->renderh=((((ULONG)sn->renderh)<<1)+sn->renderh)>>2;
  1046.  
  1047.       continue;
  1048.     }
  1049.  
  1050.     printfault(errorcode,&activescreen->fn->name[0]);
  1051.  
  1052.     /* This screen couldn't be opened, not even after closing the current screen
  1053.        (if it was available) */
  1054.  
  1055.     if(sn->node.ln_Succ->ln_Succ!=0) {
  1056.       /* This isn't the screen which is currently being decoded
  1057.          so we only need to delink and free the screennode */
  1058.  
  1059.       sn=freescreennode(sn);
  1060.  
  1061.       /* the while loop will attempt to retry the procedure... */
  1062.     }
  1063.     else {
  1064.       /* This is the screen currently being decoded... */
  1065.  
  1066.       return(USER_NEXTPARTIAL);
  1067.     }
  1068.   }
  1069.  
  1070.   /* Screen opened succesfully */
  1071.  
  1072.   if(cursn!=0) {
  1073.     freescreennode(cursn);
  1074.   }
  1075.   return(0);
  1076. }
  1077.  
  1078.  
  1079.  
  1080. /* This routine opens the correct screen and if necessary initializes its palette */
  1081.  
  1082. LONG openscreen(struct ScreenNode *sn) {
  1083.   ULONG colortag;
  1084.   WORD n,c;
  1085.   ULONG color;
  1086.   ULONG w,h;
  1087.   UBYTE *pal;
  1088.   struct ScrChoice *sc;
  1089.  
  1090.   sc=sn->scrchoice;
  1091.  
  1092.   if(SysBase->LibNode.lib_Version>=39) {
  1093.     colortag=SA_Colors32;
  1094.   }
  1095.   else {
  1096.     colortag=SA_Colors;
  1097.   }
  1098.   loadrgb32[0]=0;
  1099.  
  1100.   /* All this routine does is open the correct screen based on the info
  1101.      in the ScreenNode.  The errorcode returned is zero if the opening
  1102.      the screen went okay */
  1103.  
  1104.   c=1<<*sc->depth;
  1105.  
  1106.   if(sn->colorconversion==CC_GRAY) {
  1107.     if(colortag==SA_Colors) {
  1108.       for(n=0; n<c; n++) {
  1109.         color=(((255*n)/(c-1)) & 0xFF)>>4;
  1110.         loadrgb32[n<<1]=(n<<16)+color;
  1111.         loadrgb32[(n<<1)+1]=(color<<16)+color;
  1112.       }
  1113.       loadrgb32[n<<1]=0xffff0000;
  1114.     }
  1115.     else {
  1116.       loadrgb32[0]=c<<16;
  1117.       for(n=0; n<c; n++) {
  1118.         color=((255*n)/(c-1)) & 0xFF;
  1119.         color=(color<<24)+(color<<16)+(color<<8)+color;
  1120.         loadrgb32[n*3+1]=color;
  1121.         loadrgb32[n*3+2]=color;
  1122.         loadrgb32[n*3+3]=color;
  1123.       }
  1124.       loadrgb32[c*3+1]=0;
  1125.     }
  1126.     sn->bestpen=c-1;
  1127.   }
  1128.   else if(sn->colorconversion==CC_FTC) {
  1129.     UBYTE r,g,b,rm,gm,bm,rl,gl,bl;
  1130.  
  1131.     r=ftctable[*sc->depth*3-3];
  1132.     g=ftctable[*sc->depth*3-2];
  1133.     b=ftctable[*sc->depth*3-1];
  1134.  
  1135.     rm=((1<<r)-1)<<g<<b;
  1136.     gm=((1<<g)-1)<<b;
  1137.     bm=((1<<b)-1);
  1138.  
  1139.     rl=16-r-g-b;
  1140.     gl=16-g-b;
  1141.     bl=16-b;
  1142.  
  1143.     if(colortag==SA_Colors) {
  1144.       for(n=0; n<c; n++) {
  1145.         color=(n & rm)<<rl;
  1146.         color=color+(color>>r);
  1147.         color=color+(color>>r*2);
  1148.         loadrgb32[(n<<1)]=(n<<16)+(color>>12);
  1149.  
  1150.         color=(n & gm)<<gl;
  1151.         color=color+(color>>g);
  1152.         color=color+(color>>g*2);
  1153.         loadrgb32[(n<<1)+1]=(color>>12)<<16;
  1154.  
  1155.         color=(n & bm)<<bl;
  1156.         color=color+(color>>b);
  1157.         color=color+(color>>b*2);
  1158.         loadrgb32[(n<<1)+1]|=(color>>12);
  1159.       }
  1160.       loadrgb32[n<<1]=0xffff0000;
  1161.     }
  1162.     else {
  1163.       loadrgb32[0]=c<<16;
  1164.       for(n=0; n<c; n++) {
  1165.         color=(n & rm)<<rl<<16;
  1166.         color=color+(color>>r);
  1167.         color=color+(color>>r*2);
  1168.         color=color+(color>>r*4);
  1169.         loadrgb32[n*3+1]=color;
  1170.  
  1171.         color=(n & gm)<<gl<<16;
  1172.         color=color+(color>>g);
  1173.         color=color+(color>>g*2);
  1174.         color=color+(color>>g*4);
  1175.         loadrgb32[n*3+2]=color;
  1176.  
  1177.         color=(n & bm)<<bl<<16;
  1178.         color=color+(color>>b);
  1179.         color=color+(color>>b*2);
  1180.         color=color+(color>>b*4);
  1181.         loadrgb32[n*3+3]=color;
  1182.       }
  1183.       loadrgb32[c*3+1]=0;
  1184.     }
  1185.     sn->bestpen=c-1;
  1186.   }
  1187.   else if(sn->colorconversion==CC_PALETTE) {
  1188.     WORD diff,bestdiff=0;
  1189.     WORD r,g,b;
  1190.  
  1191.     c=sn->colors;
  1192.     pal=sn->palette;
  1193.  
  1194.     if(colortag==SA_Colors) {
  1195.       for(n=0; n<c; n++) {
  1196.         color=(*(UWORD *)pal++)>>4;
  1197.         loadrgb32[n<<1]=(n<<16)+color;
  1198.         color=(*pal++)>>4;
  1199.         loadrgb32[(n<<1)+1]=(color<<16);
  1200.         color=(*pal++)>>4;
  1201.         loadrgb32[(n<<1)+1]+=color;
  1202.       }
  1203.       loadrgb32[n<<1]=0xffff0000;
  1204.     }
  1205.     else {
  1206.       loadrgb32[0]=c<<16;
  1207.       for(n=0; n<c; n++) {
  1208.         color=*(UWORD *)pal;
  1209.         pal+=2;
  1210.         color=(color<<24)+(color<<16)+(color<<8)+color;
  1211.         loadrgb32[n*3+1]=color;
  1212.         color=*pal++;
  1213.         color=(color<<24)+(color<<16)+(color<<8)+color;
  1214.         loadrgb32[n*3+2]=color;
  1215.         color=*pal++;
  1216.         color=(color<<24)+(color<<16)+(color<<8)+color;
  1217.         loadrgb32[n*3+3]=color;
  1218.       }
  1219.       loadrgb32[c*3+1]=0;
  1220.     }
  1221.  
  1222.     pal=sn->palette;
  1223.  
  1224.     r=*(UWORD *)pal;
  1225.     pal+=2;
  1226.     g=*pal++;
  1227.     b=*pal++;
  1228.  
  1229.     for(n=1; n<c; n++) {
  1230.       color=*(UWORD *)pal;
  1231.       pal+=2;
  1232.       diff=__builtin_abs(r-color);
  1233.       diff+=__builtin_abs(g-*pal++);
  1234.       diff+=__builtin_abs(b-*pal++);
  1235.       if(diff>bestdiff) {
  1236.         bestdiff=diff;
  1237.         sn->bestpen=n;
  1238.       }
  1239.     }
  1240.   }
  1241.   else {
  1242.     if(colortag==SA_Colors) {
  1243.       loadrgb32[0]=0;
  1244.       loadrgb32[1]=0;
  1245.       loadrgb32[2]=(1<<16)+0xf;
  1246.       loadrgb32[3]=(0x0f<<16)+0x0f;
  1247.       loadrgb32[4]=0xffff0000;
  1248.     }
  1249.     else {
  1250.       loadrgb32[0]=2<<16;
  1251.       loadrgb32[1]=0;
  1252.       loadrgb32[2]=0;
  1253.       loadrgb32[3]=0;
  1254.       loadrgb32[4]=0xffffffff;
  1255.       loadrgb32[5]=0xffffffff;
  1256.       loadrgb32[6]=0xffffffff;
  1257.       loadrgb32[7]=0;
  1258.     }
  1259.     sn->bestpen=1;
  1260.   }
  1261.  
  1262.   /* renderw and renderh in combination with width and height of the ScreenNode structure
  1263.      determine the scaling factors. */
  1264.  
  1265.   sn->scalexfactor=(((ULONG)sn->renderw)<<12)/sn->width;
  1266.   sn->scaleyfactor=(((ULONG)sn->renderh)<<12)/sn->height;
  1267.  
  1268.  
  1269.   w=(sn->renderw+31) & 0xffffffe0;
  1270.   h=(sn->renderh+wbfontysize+7) & 0xfffffff8;
  1271.  
  1272.   if(w<*sn->scrchoice->nomw) {
  1273.     w=*sn->scrchoice->nomw;
  1274.   }
  1275.   if(h<128) {
  1276.     h=128;
  1277.   }
  1278.  
  1279.   if(arglist.debug!=0) {
  1280.     ULONG arg[4];
  1281.  
  1282.     arg[0]=w;
  1283.     arg[1]=h;
  1284.     arg[2]=*sc->depth;
  1285.     arg[3]=sc->modeid;
  1286.     VPrintf("(DEBUG) OpenScreen: %ldx%ldx%ld  ModeID: $%08lx\n",&arg);
  1287.   }
  1288.  
  1289.   /* A big hack to prevent the default screenfont opencount from reaching zero
  1290.      when a screen failed to open */
  1291.  
  1292.   GfxBase->DefaultFont->tf_Accessors++;
  1293.  
  1294.   if((sn->screen=OpenScreenTags(0,SA_Left,0,SA_Width,w,SA_Height,h,SA_BackFill,LAYERS_NOBACKFILL,
  1295.                                   SA_Depth,*sc->depth,SA_Quiet,TRUE,SA_DisplayID,sn->modeid,
  1296.                                   SA_Overscan,OSCAN_STANDARD,SA_AutoScroll,TRUE,SA_Font,wbscr->Font,
  1297.                                   colortag,&loadrgb32,TAG_DONE))!=0) {
  1298.  
  1299.     GfxBase->DefaultFont->tf_Accessors--;
  1300.  
  1301.     if((sn->window=OpenWindowTags(0,WA_IDCMP,IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY,
  1302. //                                    WA_BackFill,&bfillhook,   or WA_BackFill, LAYERS_NOBACKFILL
  1303.                                     WA_Borderless,TRUE,WA_Activate,TRUE,WA_RMBTrap,TRUE,
  1304.                                     WA_CustomScreen,sn->screen,TAG_DONE))!=0) {
  1305.  
  1306.  
  1307.       if(sn->tempbm=CreateBitMap(sn->width,8,BitMapDepth(sn->screen->RastPort.BitMap))) {
  1308.         struct Node *node;
  1309.  
  1310.         InitRastPort(&sn->temprp);
  1311.         sn->temprp.BitMap=sn->tempbm;
  1312.  
  1313.         /* We load the palette again here because some gfx-cards use a 12-bit palette
  1314.            with the SA_Colors32 tag passed to OpenScreen() */
  1315.  
  1316.         if(colortag==SA_Colors32) {
  1317.           LoadRGB32(&sn->screen->ViewPort,(ULONG *)&loadrgb32);
  1318.         }
  1319.  
  1320.         infotext(sn);
  1321.  
  1322.         /* Display any data available in the DisplayData structure and free it */
  1323.  
  1324.         while(sn->displaydata.lh_Head->ln_Succ!=0) {
  1325.           node=sn->displaydata.lh_Head;
  1326.  
  1327.           displaypicture(sn,(struct DisplayData *)node);
  1328.  
  1329.           Remove(node);
  1330.           FreeVec(node);
  1331.         }
  1332.  
  1333.         /* Everything went okay */
  1334.  
  1335.         activescreen=sn;
  1336.  
  1337.         return(0);
  1338.       }
  1339.     }
  1340.     else {
  1341.       return(ERROR_NO_WINDOW);
  1342.     }
  1343.   }
  1344.   else {
  1345.     return(ERROR_NO_SCREEN);
  1346.   }
  1347. }
  1348.  
  1349.  
  1350. void infotext(struct ScreenNode *sn) {
  1351.   /* Display the info text above the picture if wanted */
  1352.  
  1353.   if(arglist.info!=0) {
  1354.     UBYTE str[256];
  1355.  
  1356.     SetAPen(sn->window->RPort,0);
  1357.     RectFill(sn->window->RPort,0,0,sn->screen->Width-1,wbfontysize-1);
  1358.  
  1359.     makeinfostring(&str[0],par_info,256,sn);
  1360.  
  1361.     SetAPen(sn->window->RPort,sn->bestpen);
  1362.     Move(sn->window->RPort,0,sn->window->RPort->TxBaseline);
  1363.     Text(sn->window->RPort,str,strlen(str));
  1364.   }
  1365. }
  1366.  
  1367.  
  1368. /* Closes the screen and releases any other resources allocated by openscreen.
  1369.    This routine is safe to call even if no screen or resources have been allocated. */
  1370.  
  1371. void closescreen(struct ScreenNode *sn) {
  1372.  
  1373.   DeleteBitMap(sn->tempbm);
  1374.   sn->tempbm=0;
  1375.  
  1376.   if(sn->window!=0) {
  1377.     CloseWindow(sn->window);
  1378.     sn->window=0;
  1379.   }
  1380.  
  1381.   if(sn->screen!=0) {
  1382.     CloseScreen(sn->screen);
  1383.     sn->screen=0;
  1384.   }
  1385. }
  1386.  
  1387.  
  1388.  
  1389. /* Deallocates a ScreenNode completely and all resources (if any) associated
  1390.    with it.  It returns the next ScreenNode, or 0 if there is none */
  1391.  
  1392. struct ScreenNode *freescreennode(struct ScreenNode *sn) {
  1393.   struct ScreenNode *nextsn;
  1394.   struct Node *node;
  1395.  
  1396.   /* First close the screen (if any) */
  1397.   closescreen(sn);
  1398.  
  1399.   if(sn->fh!=0) {
  1400.     Close(sn->fh);
  1401.   }
  1402.  
  1403.   while(sn->displaydata.lh_Head->ln_Succ!=0) {
  1404.     node=sn->displaydata.lh_Head;
  1405.  
  1406.     Remove(node);
  1407.     FreeVec(node);
  1408.   }
  1409.  
  1410.   nextsn=(struct ScreenNode *)sn->node.ln_Succ;
  1411.  
  1412.   /* Delink this node from the list */
  1413.   Remove((struct Node *)sn);
  1414.  
  1415.  
  1416.   /* Free the ScreenNode structure */
  1417.   FreeVec(sn);
  1418.  
  1419.   return(nextsn);
  1420. }
  1421.  
  1422.  
  1423.  
  1424.  
  1425. /* This routine scans through the ScrChoice structures and returns a pointer
  1426.    to the one best matching the requirements.  It also sets some fields in the
  1427.    ScreenNode structure for the conversion and rendering routines. */
  1428.  
  1429. struct ScrChoice *bestmodeid(struct ScreenNode *sn) {
  1430.  
  1431.   struct ScrChoice *sc;
  1432.   struct ScrChoice *bestsc;
  1433.   LONG a;
  1434.   LONG cursize,bestsize=0x7fffffff;
  1435.   UBYTE curcc,bestcc=0;
  1436.   UBYTE flag;
  1437.  
  1438.   sc=firstscrchoice;
  1439.   bestsc=0;
  1440.  
  1441.   while(sc!=0) {
  1442.     if(sc->modeid!=INVALID_ID) {
  1443.  
  1444.       /* Compare size of picture with the size of the screen; penalties are given
  1445.          if the screen is too big or too small */
  1446.  
  1447.       a=*sc->nomw-sn->width;
  1448.       if(a<0) {
  1449.         a=-4*a;
  1450.       }
  1451.       cursize=*sc->nomh-sn->height;
  1452.       if(cursize<0) {
  1453.         cursize=-4*cursize;
  1454.       }
  1455.       cursize+=a;
  1456.  
  1457.       /* Check what kind of ColorConversion is needed to display the picture onto this
  1458.          screen */
  1459.  
  1460.       if(sn->colorinput==CI_PALETTE) {
  1461.         if(sn->depth<=*sc->depth) {
  1462.           curcc=CC_PALETTE;
  1463.         }
  1464.         else {
  1465.           curcc=CC_UNKNOWN;
  1466.         }
  1467.       }
  1468.       else if(sn->colorinput==CI_GRAY) {
  1469.         if(*sc->depth<=8) {
  1470.           curcc=CC_GRAY;
  1471.         }
  1472.         else {
  1473.           curcc=CC_UNKNOWN;
  1474.         }
  1475.       }
  1476.       else if(sn->colorinput==CI_RGB) {
  1477.         if(*sc->depth<=8) {
  1478.           curcc=CC_FTC;
  1479.         }
  1480.         else {
  1481.           curcc=CC_TRUECOLOR;
  1482.         }
  1483.       }
  1484.       else {
  1485.         curcc=CC_UNKNOWN;
  1486.       }
  1487.  
  1488.       /* Now see if this mode is better suited than a previously found mode (if any) */
  1489.  
  1490.       flag=0;
  1491.  
  1492.       if(arglist.debug!=0) {
  1493.         ULONG arg[4];
  1494.  
  1495.         if(bestsc!=0) {
  1496.           arg[0]=bestsc->modeid;
  1497.         }
  1498.         else {
  1499.           arg[0]=0;
  1500.         }
  1501.         arg[1]=cursize;
  1502.         arg[2]=sn->colorinput;
  1503.         arg[3]=curcc;
  1504.  
  1505.         VPrintf("(DEBUG) bestmodeid: $%08lx cursize: %5ld colorin: %3ld colorconv: %3ld\n",&arg);
  1506.       }
  1507.  
  1508.       if(curcc!=CC_UNKNOWN) {
  1509.         if(sn->colorinput==CI_RGB) {
  1510.           if(curcc==CC_TRUECOLOR) {
  1511.             if(bestcc!=CC_TRUECOLOR || cursize<bestsize) {
  1512.               flag=1;
  1513.             }
  1514.           }
  1515.           else if(bestcc!=CC_TRUECOLOR && cursize<bestsize) {
  1516.             flag=1;
  1517.           }
  1518.         }
  1519.         else if(sn->colorinput==CI_PALETTE) {
  1520.           /* if input is CI_PALETTE and output-depth is good enough to display the palette but
  1521.              less than the bestoutput-depth then set flag */
  1522.  
  1523.           if(*sc->depth>=sn->depth && (bestsc==0 || *bestsc->depth>*sc->depth)) {
  1524.             flag=1;
  1525.           }
  1526.  
  1527.           if(cursize<bestsize) {
  1528.             flag=1;
  1529.           }
  1530.         }
  1531.         else if(sn->colorinput==CI_GRAY) {
  1532.           if(cursize<bestsize) {
  1533.             flag=1;
  1534.           }
  1535.         }
  1536.       }
  1537.  
  1538.       if(flag!=0) {
  1539.         bestsc=sc;
  1540.         bestcc=curcc;
  1541.         bestsize=cursize;
  1542.       }
  1543.     }
  1544.     sc=sc->next;
  1545.   }
  1546.  
  1547.   sn->colorconversion=bestcc;
  1548.   sn->renderd=*bestsc->depth;
  1549.  
  1550.   return(bestsc);
  1551. }
  1552.  
  1553.  
  1554.  
  1555. /* Special print-fault replacement */
  1556.  
  1557. void printfault(LONG errorcode,UBYTE *header) {
  1558.   if(errorcode>20 && errorcode<50) {
  1559.     VPrintf("%s: ",&header);
  1560.     switch(errorcode) {
  1561.       case ERROR_INVALID_FILE:
  1562.         PutStr("File is invalid\n"); break;
  1563.       case ERROR_EMPTY_FILE:
  1564.         PutStr("File does not contain any pictures\n"); break;
  1565.       case ERROR_NO_SCREEN:
  1566.         PutStr("Couldn't open a screen\n"); break;
  1567.       case ERROR_NO_WINDOW:
  1568.         PutStr("Couldn't open a window\n"); break;
  1569.       case ERROR_WHILE_DECODING:
  1570.         PutStr("Error while decoding; file may be corrupt\n"); break;
  1571.       case ERROR_EARLY_END_OF_FILE:
  1572.         PutStr("Unexpected end of file encountered; file may be corrupt\n"); break;
  1573.       case ERROR_END_OF_STREAM:
  1574.         PutStr("Unexpected end of encoded data; file may be corrupt\n"); break;
  1575.       case ERROR_UNKNOWN_FILETYPE:
  1576.         PutStr("Filetype not recognized\n"); break;
  1577.       case ERROR_NO_SCREENMODE:
  1578.         PutStr("No suitable screenmode found\n"); break;
  1579.     }
  1580.   }
  1581.   else {
  1582.     PrintFault(errorcode,header);
  1583.   }
  1584. }
  1585.  
  1586.  
  1587.  
  1588. /* Loads data from disk for easy access by the decoding routines.  The minsize
  1589.    parameter passed to initloader determines the minimum amount of bytes which
  1590.    should be present in the buffer before returning (this will be rounded up to
  1591.    some comfortable number if necessary).  This routine returns a (DOS) errorcode
  1592.    in case of failure or zero if everything went okay. */
  1593.  
  1594. LONG doloader(struct ScreenNode *sn) {
  1595.   ULONG temp,size;
  1596.   LONG res;
  1597.  
  1598.   if(sn->fileptr > sn->loaderbuf+sn->loaderbufsize/2) {
  1599.     /* There aren't enough bytes in the buffer to fill the demand.  We will need
  1600.        to move the resting portion of the buffer to the start of the buffer, and
  1601.        fill the newly created void with data from the file. */
  1602.  
  1603.     temp=(ULONG)sn->fileptr & 0xfffffff8;
  1604.     size=(ULONG)(sn->loaderbuf+sn->loaderbufsize-temp);
  1605.  
  1606.     CopyMemQuick((ULONG *)temp,sn->loaderbuf,size);
  1607.  
  1608.     sn->fileptr-=sn->loaderbufsize-size;
  1609.  
  1610.     if((res=Read(sn->fh,sn->loaderbuf+size,sn->loaderbufsize-size))==-1) {
  1611.       return(IoErr());
  1612.     }
  1613.     sn->bytesinloaderbuf=size+res;
  1614.   }
  1615.  
  1616.   if(sn->loaderbuf+sn->bytesinloaderbuf<sn->fileptr) {
  1617.     /* The fileptr is located beyond the end of the file, return an error! */
  1618.     return(ERROR_EARLY_END_OF_FILE);
  1619.   }
  1620.  
  1621.   return(0);
  1622. }
  1623.  
  1624.  
  1625.  
  1626. /* minsize is the number of bytes which the doloader routine should atleast have present
  1627.    in the loaderbuffer at exit of the routine for proper functioning of the routine which
  1628.    make use of the buffering routines. */
  1629.  
  1630. LONG initloader(struct ScreenNode *sn,ULONG minsize) {
  1631.   sn->loaderbufsize=((minsize+2047) & 0xfffff800)*2;
  1632.  
  1633.   if((sn->loaderbuf=AllocVec(sn->loaderbufsize,MEMF_ANY))!=0) {
  1634.     sn->fileptr=sn->loaderbuf;
  1635.     if((sn->bytesinloaderbuf=Read(sn->fh,sn->loaderbuf,sn->loaderbufsize))==-1) {
  1636.       return(IoErr());
  1637.     }
  1638.   }
  1639.   else {
  1640.     return(ERROR_NO_FREE_STORE);
  1641.   }
  1642.   return(0);
  1643. }
  1644.  
  1645.  
  1646.  
  1647. /* freeloader frees all resources allocated by initloader.  It is safe to call this
  1648.    even if initloader was never called.  This function must be called if initloader
  1649.    was called, even if initloader returned an error. */
  1650.  
  1651. void freeloader(struct ScreenNode *sn) {
  1652.   if(sn->loaderbuf!=0) {
  1653.     FreeVec(sn->loaderbuf);
  1654.     sn->loaderbuf=0;
  1655.   }
  1656. }
  1657.  
  1658.  
  1659.  
  1660. BOOL recogniseGIF(struct ScreenNode *sn) {
  1661.   UBYTE buf[6];
  1662.  
  1663.   if(Read(sn->fh,buf,6)==6) {
  1664.     if((buf[0]=='G') && (buf[1]=='I') && (buf[2]=='F') && (buf[3]=='8')) {
  1665.       if((buf[4]=='7') || (buf[4]=='9')) {
  1666.         if(buf[5]=='a') {
  1667.           return(TRUE);
  1668.         }
  1669.       }
  1670.     }
  1671.   }
  1672.   return(FALSE);
  1673. }
  1674.  
  1675.  
  1676.  
  1677. struct GIF {
  1678.   WORD size;        // initial code size, also used when a clear-code is detected
  1679.   WORD cursize;
  1680.   WORD clearcode;
  1681.   WORD endcode;
  1682.   WORD newcodes;
  1683.   WORD topslot;
  1684.   WORD slot;
  1685.   WORD navailbytes;
  1686.   WORD nbitsleft;
  1687.   WORD shiftreg;
  1688.   UBYTE *suffix;
  1689.   UWORD *prefix;
  1690.   UBYTE *stack;
  1691.   UBYTE *sp;
  1692.   UWORD oc;
  1693.   UWORD fc;
  1694.   UWORD row;
  1695.   UBYTE interlaced;
  1696. };
  1697.  
  1698.  
  1699.  
  1700. LONG initGIF(struct ScreenNode *sn) {
  1701.   UBYTE buf[10];
  1702.   UBYTE tempcmap[256*3];
  1703.   ULONG colmapsize;
  1704.   LONG errorcode;
  1705.   struct GIF *data;
  1706.  
  1707.   data=(struct GIF *)&sn->data;
  1708.  
  1709.   if(Read(sn->fh,buf,7)==7) {
  1710.     sn->depth=(buf[4] & 0x07)+1;
  1711.     sn->colors=1<<sn->depth;
  1712.  
  1713.     if((buf[4] & 0x80)!=0) {
  1714.       colmapsize=sn->colors*3;
  1715.       if(Read(sn->fh,tempcmap,colmapsize)==colmapsize) {
  1716.         copypalette(sn,tempcmap);
  1717.       }
  1718.       else {
  1719.         return(ERROR_INVALID_FILE);
  1720.       }
  1721.     }
  1722.  
  1723.     for(;;) {
  1724.       if(Read(sn->fh,buf,2)!=2) {
  1725.         return(ERROR_INVALID_FILE);
  1726.       }
  1727.       if(buf[0]=='!') {
  1728.  
  1729.         for(;;) {
  1730.           if(Read(sn->fh,buf,1)!=1) {
  1731.             return(ERROR_INVALID_FILE);
  1732.           }
  1733.           if(buf[0]==0) {
  1734.             break;
  1735.           }
  1736.           if(Seek(sn->fh,(LONG)buf[0],OFFSET_CURRENT)==-1) {
  1737.             return(IoErr());
  1738.           }
  1739.         }
  1740.  
  1741.       }
  1742.       else {
  1743.         break;
  1744.       }
  1745.     }
  1746.  
  1747.     if(buf[0]==',') {
  1748.       if(Read(sn->fh,&buf[2],8)==8) {
  1749.         sn->height=(UWORD)buf[7]+((UWORD)buf[8]<<8);
  1750.         sn->width=(UWORD)buf[5]+((UWORD)buf[6]<<8);
  1751.  
  1752.         if((buf[9] & 0x80)!=0) {
  1753.           sn->depth=(buf[9] & 0x07)+1;
  1754.           sn->colors=1<<sn->depth;
  1755.  
  1756.           colmapsize=sn->colors*3;
  1757.           if(Read(sn->fh,tempcmap,colmapsize)==colmapsize) {
  1758.             copypalette(sn,tempcmap);
  1759.           }
  1760.           else {
  1761.             return(ERROR_INVALID_FILE);
  1762.           }
  1763.         }
  1764.  
  1765.         if((buf[9] & 0x40)!=0) {
  1766.           data->interlaced=4;
  1767.         }
  1768.         else {
  1769.           data->interlaced=0;
  1770.         }
  1771.  
  1772.         sn->bytesperrow=sn->width;
  1773.         sn->bytesperpixel=1;
  1774.         sn->colorinput=CI_PALETTE;
  1775.  
  1776.         sn->aspectx=640;
  1777.         sn->aspecty=480;
  1778.  
  1779.         /* All done, now follows the actual "raster data", all that rests now is
  1780.            to init some variables for the decoder. */
  1781.  
  1782.         if((errorcode=initloader(sn,((ULONG)sn->width)<<4))==0) {
  1783.           data->size=*sn->fileptr++;
  1784.           if(data->size<2 || data->size>9) {
  1785.             return(ERROR_INVALID_FILE);
  1786.           }
  1787.  
  1788.           data->cursize=data->size+1;
  1789.           data->topslot=1<<data->cursize;
  1790.           data->clearcode=1<<data->size;
  1791.           data->endcode=data->clearcode+1;
  1792.           data->slot=data->newcodes=data->endcode+1;
  1793.           data->navailbytes=data->nbitsleft=0;
  1794.  
  1795.           if((data->suffix=AllocVec(4096+4096+8192,MEMF_CLEAR))!=0) {
  1796.             data->prefix=(UWORD *)(data->suffix+8192);
  1797.             data->stack=data->suffix+4096;
  1798.             data->sp=data->stack;
  1799.  
  1800.             return(0);
  1801.           }
  1802.           return(ERROR_NO_FREE_STORE);
  1803.         }
  1804.         return(errorcode);
  1805.       }
  1806.     }
  1807.   }
  1808.  
  1809.   return(ERROR_INVALID_FILE);
  1810. }
  1811.  
  1812.  
  1813.  
  1814. void exitGIF(struct ScreenNode *sn) {
  1815.   struct GIF *data;
  1816.  
  1817.   data=(struct GIF *)&sn->data;
  1818.  
  1819.   freeloader(sn);
  1820.   FreeVec(data->suffix);
  1821. }
  1822.  
  1823.  
  1824.  
  1825.  
  1826. void copypalette(struct ScreenNode *sn,UBYTE *pal) {
  1827.   UBYTE *palptr;
  1828.   UWORD n;
  1829.  
  1830.   palptr=sn->palette;
  1831.   for(n=0;n<sn->colors;n++) {
  1832.     *(UWORD *)palptr=*pal++;
  1833.     palptr+=2;
  1834.     *palptr++=*pal++;
  1835.     *palptr++=*pal++;
  1836.   }
  1837. }
  1838.  
  1839.  
  1840. BOOL recogniseJPEG(struct ScreenNode *sn) {
  1841.   if(FGetC(sn->fh)==0xFF) {
  1842.     if(FGetC(sn->fh)==0xD8) {
  1843.       return(TRUE);
  1844.     }
  1845.   }
  1846.  
  1847. //  if(TowerBase!=0) {
  1848. //  }
  1849.  
  1850.   return(FALSE);
  1851. }
  1852.  
  1853.  
  1854. struct JPEG {
  1855.   APTR obj;
  1856.   UWORD row;
  1857. }; /* do not exceed 44 bytes */
  1858.  
  1859.  
  1860. LONG initJPEG(struct ScreenNode *sn) {
  1861.   struct JPEG *data;
  1862.   ULONG error;
  1863.   ULONG colorspace,width,height;
  1864.  
  1865.   data=(struct JPEG *)&sn->data;
  1866.   Seek(sn->fh,0,OFFSET_BEGINNING);
  1867.  
  1868.   if(data->obj=NewExtObject(JPEGCODEC,CDA_StreamType,CDST_FILE,
  1869.                                       CDA_Stream,sn->fh,TAG_DONE)) {
  1870.     if((error=DoMethod(data->obj,CDM_READHEADER))==HEADER_READY) {
  1871.       if(GetAttr(PCDA_ColorSpace,data->obj,&colorspace)
  1872.          && GetAttr(PCDA_Width,data->obj,&width)
  1873.          && GetAttr(PCDA_Height,data->obj,&height)) {
  1874.         sn->width=width;
  1875.         sn->height=height;
  1876.         if(colorspace!=PCDCS_GRAYSCALE) {
  1877.           colorspace=PCDCS_RGB;
  1878.           sn->depth=24;
  1879.           sn->bytesperrow=sn->width*3;
  1880.           sn->bytesperpixel=3;
  1881.           sn->colorinput=CI_RGB;
  1882.         }
  1883.         else {
  1884.           sn->depth=8;
  1885.           sn->colors=256;
  1886.           sn->bytesperrow=sn->width;
  1887.           sn->bytesperpixel=1;
  1888.           sn->colorinput=CI_GRAY;
  1889.         }
  1890.         SetAttrs(data->obj,PCDA_ColorSpace,colorspace,TAG_DONE);
  1891.         if(DoMethod(data->obj,CDM_START)!=0) {
  1892.           sn->truecolor=TRUE;
  1893.           sn->aspectx=640;
  1894.           sn->aspecty=480;
  1895.           return(0);
  1896.         }
  1897.         else {
  1898.           return(ERROR_NO_FREE_STORE);
  1899.         }
  1900.       }
  1901.       else {
  1902.         return(ERROR_INVALID_FILE);
  1903.       }
  1904.     }
  1905.     else if(error==HEADER_EMPTY) {
  1906.       return(ERROR_EMPTY_FILE);
  1907.     }
  1908.     else {
  1909.       return(ERROR_INVALID_FILE);
  1910.     }
  1911.   }
  1912.   else {
  1913.     return(ERROR_NO_FREE_STORE);
  1914.   }
  1915. }
  1916.  
  1917.  
  1918. void exitJPEG(struct ScreenNode *sn) {
  1919.   struct JPEG *data;
  1920.  
  1921.   data=(struct JPEG *)&sn->data;
  1922.   if(data->obj!=0) {
  1923.     DisposeExtObject(data->obj);
  1924.   }
  1925. }
  1926.  
  1927.  
  1928. /* The decode functions return an errorcode if something went wrong during the
  1929.    decoding process. */
  1930.  
  1931. LONG __asm decodeJPEG(register __a0 struct ScreenNode *sn,register __d0 UWORD rows,register __a1 UBYTE *buffer) {
  1932.   struct JPEG *data;
  1933.   struct LineHeader *lh=(struct LineHeader *)(buffer-(sizeof(struct LineHeader)<<3));
  1934.  
  1935.   data=(struct JPEG *)&sn->data;
  1936.  
  1937.   while(rows--!=0) {
  1938.     if(DoMethod(data->obj,CDM_PROCESS,buffer,sn->bytesperrow)!=sn->bytesperrow) {
  1939.       return(ERROR_WHILE_DECODING);
  1940.     }
  1941.     buffer+=sn->bytesperrow;
  1942.     lh->row=data->row++;
  1943.     lh->repeatrow=1;
  1944.     lh++;
  1945.   }
  1946.   return(0);
  1947. }
  1948.  
  1949.  
  1950.  
  1951.  
  1952. LONG decodepicture(struct ScreenNode *sn,struct PicType *pictype) {
  1953.   UBYTE *buf;
  1954.   UWORD row=0;
  1955.   UWORD rowstodec;
  1956.   LONG  errorcode=0;
  1957.  
  1958.   struct DisplayData *dd=0;
  1959.  
  1960.   while((rowstodec=sn->height-row)>0) {
  1961.  
  1962.     if((errorcode=checkmsg())!=0) {
  1963.       break;
  1964.     }
  1965.  
  1966.     if((errorcode=doloader(sn))!=0) {
  1967.       break;
  1968.     }
  1969.  
  1970.     if(rowstodec>8) {
  1971.       rowstodec=8;
  1972.     }
  1973.  
  1974.  
  1975.     while(dd==0) {
  1976.       if(sn->screen!=0 || AvailMem(MEMF_FAST)>leavemem) {
  1977.         if((dd=(struct DisplayData *)AllocVec(sizeof(struct DisplayData)+sn->bytesperrow*8,0))!=0) {
  1978.           buf=(UBYTE *)dd+sizeof(struct DisplayData);
  1979.           dd->node.ln_Succ=0;
  1980.           dd->node.ln_Pred=0;
  1981.           dd->row=row;
  1982.           dd->rowstodec=rowstodec;
  1983.         }
  1984.       }
  1985.       if(sn->screen!=0 || dd!=0) {
  1986.         break;
  1987.       }
  1988.  
  1989.       /* This isn't the picture currently being displayed, and there either was too little
  1990.          memory left to allocate the buffer, the largest block was too small or no memory
  1991.          was allocated because of the leavemem limit.  In any case, no buffer has been
  1992.          allocated and we need to wait until more memory is available before retrying. */
  1993.  
  1994.       WaitPort(activescreen->window->UserPort);
  1995.       if((errorcode=checkmsg())!=0) {
  1996.         break;
  1997.       }
  1998.     }
  1999.  
  2000.     /* als errorcode al ongelijk nul was (bijv. USER_EXIT) dan break */
  2001.     if(errorcode!=0) {
  2002.       break;
  2003.     }
  2004.  
  2005.     if(dd==0) {
  2006.       errorcode=ERROR_NO_FREE_STORE;
  2007.       break;
  2008.     }
  2009.  
  2010.     errorcode=pictype->decodefunc(sn,rowstodec,buf);
  2011.  
  2012.     if(sn->colorconversion==CC_FTC) {
  2013.       RGBTOFTC(buf,buf,sn->width,rowstodec,sn->renderd);
  2014.       sn->colorinput=CI_PALETTE;
  2015.     }
  2016.  
  2017.     /* check if there is a screen for this ScreenNode, if not then store the decoded data */
  2018.  
  2019.     if(sn->screen!=0) {
  2020.       dd->row=row;
  2021.       dd->rowstodec=rowstodec;
  2022.  
  2023.       displaypicture(sn,dd);
  2024.     }
  2025.     else {
  2026.       AddTail(&sn->displaydata,&dd->node);
  2027.       dd=0;   /* make sure a new buffer is allocated */
  2028.     }
  2029.  
  2030.     row+=rowstodec;
  2031.  
  2032.     if(errorcode!=0) {
  2033.       break;
  2034.     }
  2035.  
  2036.   }
  2037.   FreeVec(dd);
  2038.  
  2039.   if(errorcode==0 && rowstodec!=0) {
  2040.     return(ERROR_WHILE_DECODING);
  2041.   }
  2042.   return(errorcode);
  2043. }
  2044.  
  2045. /*
  2046.                 RECTFMT_LUT8  1 byte per pixel, specifying the pen
  2047.                                   number. On screen depths > 8 bits the
  2048.                               data is converted using the actual color
  2049.                               lookup table.
  2050.  
  2051.                 RECTFMT_GREY8 1 byte per pixel, specifying grey scale
  2052.                               value.
  2053. */
  2054.  
  2055.  
  2056.  
  2057. /* This routine gets as input a struct ScreenNode * and a pointer to the data to be
  2058.    displayed.  This can be data which has just been decoded and needs to be displayed
  2059.    immediately, but it could just as well be data that has been stored for later display */
  2060.  
  2061. void displaypicture(struct ScreenNode *sn,struct DisplayData *dd) {
  2062.   WORD offsetleft;
  2063.   UBYTE *buf;
  2064.   UBYTE *scalebuf=0;
  2065.   ULONG format;
  2066.   UWORD bpr;
  2067.   UWORD row=dd->row;
  2068.   UBYTE repeatrow;
  2069.   UWORD drawrow;
  2070.   UWORD rowstodec=dd->rowstodec;
  2071.   UBYTE cybertrue=(CyberGfxBase!=0 && IsCyberModeID(sn->modeid));
  2072.   LONG scalemul;
  2073.   LONG scalemasked;
  2074.   struct LineHeader *lh=dd->lh;
  2075.  
  2076.   buf=(UBYTE *)dd+sizeof(struct DisplayData);
  2077.  
  2078.   if(sn->colorinput==CI_PALETTE || sn->colorinput==CI_GRAY) {
  2079.     format=RECTFMT_LUT8;
  2080.     bpr=sn->width;
  2081.   }
  2082.   else {
  2083.     format=RECTFMT_RGB;
  2084.     bpr=sn->width*3;
  2085.   }
  2086.  
  2087.   offsetleft=(*sn->scrchoice->nomw-sn->renderw)>>1;
  2088.   if(offsetleft<0) {
  2089.     offsetleft=0;
  2090.   }
  2091.  
  2092.   if(sn->scalexfactor==4096 || (scalebuf=AllocVec(sn->renderw*sn->bytesperpixel+4,MEMF_PUBLIC))!=0) {
  2093.     while(rowstodec--!=0) {
  2094.       repeatrow=lh->repeatrow;
  2095.       row=lh->row;
  2096.  
  2097.       while(repeatrow--!=0 && row<sn->height) {
  2098.         scalemul=sn->scaleyfactor*row;
  2099.         scalemasked=scalemul & 0xFFFFF000;
  2100.         scalemul+=sn->scaleyfactor;
  2101.  
  2102.         while(scalemul>scalemasked) {
  2103.           scalemul-=4096;
  2104.  
  2105. //        if((scalemul & 4095)<sn->scaleyfactor) {
  2106.  
  2107.           drawrow=(scalemul>>12)+wbfontysize;
  2108.  
  2109.           if(sn->scalexfactor!=4096) {
  2110.             if(sn->colorinput==CI_PALETTE || sn->colorinput==CI_GRAY) {
  2111.               SCALEGRAY(buf,scalebuf,sn->width,sn->scalexfactor);
  2112.             }
  2113.             else {
  2114.               SCALERGB(buf,scalebuf,sn->width,sn->scalexfactor);
  2115.             }
  2116.           }
  2117.  
  2118.           if(cybertrue!=0) {
  2119.             WritePixelArray(scalebuf!=0 ? scalebuf : buf,0,0,bpr,&sn->screen->RastPort,offsetleft,drawrow,sn->renderw,1,format);
  2120.           }
  2121.           else {
  2122.             WritePixelLine8(&sn->screen->RastPort,offsetleft,drawrow,sn->renderw,scalebuf!=0 ? scalebuf : buf,&sn->temprp);
  2123.           }
  2124.         }
  2125.         row++;
  2126.       }
  2127.  
  2128.       lh++;
  2129.       buf+=bpr;
  2130.     }
  2131.     if(scalebuf!=0) {
  2132.       FreeVec(scalebuf);
  2133.     }
  2134.   }
  2135. }
  2136.  
  2137.  
  2138. /* Works for both normal and minimal listheaders */
  2139.  
  2140. void InitList(struct List *list) {
  2141.   list->lh_Head=(struct Node *)&list->lh_Tail;
  2142.   list->lh_Tail=0;
  2143.   list->lh_TailPred=(struct Node *)&list->lh_Head;
  2144. }
  2145.  
  2146.  
  2147. ULONG __saveds __asm bfillhookfunc(register __a0 struct Hook *hook,register __a2 APTR object,register __a1 APTR message) {
  2148.   return(0);
  2149. }
  2150.  
  2151.  
  2152. struct BitMap *CreateBitMap(LONG width, LONG height, LONG depth)
  2153. {
  2154.         struct BitMap *bm;
  2155.  
  2156.  
  2157.         if(SysBase->LibNode.lib_Version>=39) {
  2158.                 bm = AllocBitMap(width, height, depth, 0, NULL);
  2159.         }
  2160.         else
  2161.         {
  2162.                 if (bm = AllocMem(sizeof(struct BitMap), MEMF_CLEAR | MEMF_PUBLIC))
  2163.                 {
  2164.                         LONG rassize = RASSIZE(width, height);
  2165.  
  2166.                         InitBitMap(bm, depth, width, height);
  2167.                         /* For simplicity, we allocate all planes in one big chunk */
  2168.                         if (bm->Planes[0] = (PLANEPTR) AllocVec(depth * rassize, MEMF_CHIP))
  2169.                         {
  2170.                                 LONG i;
  2171.  
  2172.                                 for (i = 1; i < depth; i++)
  2173.                                 {
  2174.                                         bm->Planes[i] = bm->Planes[i - 1] + rassize;
  2175.                                 }
  2176.                         }
  2177.                         else
  2178.                         {
  2179.                                 FreeMem(bm, sizeof(struct BitMap));
  2180.                                 bm = NULL;
  2181.                         }
  2182.                 }
  2183.         }
  2184.         return (bm);
  2185. }
  2186.  
  2187. static void DeleteBitMap(struct BitMap *bm)
  2188. {
  2189.         if (bm)
  2190.         {
  2191.                 if(SysBase->LibNode.lib_Version>=39) {
  2192.                         FreeBitMap(bm);
  2193.                 }
  2194.                 else
  2195.                 {
  2196.                         FreeVec(bm->Planes[0]);
  2197.                         FreeMem(bm, sizeof(struct BitMap));
  2198.                 }
  2199.         }
  2200. }
  2201.  
  2202.  
  2203. static ULONG BitMapDepth(struct BitMap *bm)
  2204. {
  2205.         if(SysBase->LibNode.lib_Version>=39) {
  2206.                 return (GetBitMapAttr(bm, BMA_DEPTH));
  2207.         }
  2208.         else
  2209.         {
  2210.                 return (bm->Depth);
  2211.         }
  2212. }
  2213.  
  2214.  
  2215. /*
  2216.  
  2217. RecogniseXXX routines:
  2218. * Inputs:
  2219.   - FileHandle
  2220. * Results:
  2221.   - TRUE (if file is valid) or FALSE
  2222.  
  2223. InitXXX routines:
  2224. * Inputs:
  2225.   - FileHandle
  2226.   - struct ScreenNode *
  2227. * Results:
  2228.   - ERROR_INVALID_FILE
  2229.   - ERROR_EMPTY_FILE
  2230.   - ERROR_UNKNOWN_COMPRESSION
  2231.   - ERROR_UNSUPPORTED_DEPTH
  2232.   - ERROR_NO_FREE_STORE
  2233.   - 0 (if file is ready to be decoded)
  2234.   - FileHandle is updated ready to be used by the DecodeXXX routine
  2235.   - struct ScreenNode * is filled with all the needed information
  2236.  
  2237. ExitXXX routines:
  2238. * Inputs:
  2239.   - struct ScreenNode *
  2240. * Purpose of these routines is to free any resources allocated by the InitXXX
  2241.   routines.
  2242.  
  2243. DecodeXXX routines:
  2244. * Inputs:
  2245.   - Callback Hook to process each decoded line (OutputLineRTN)
  2246.   - FileHandle
  2247.   - struct ScreenNode *
  2248. * Results:
  2249.   - ERROR_WHILE_DECODING (invalid data)
  2250. * Info:
  2251.   The CallBack hook returns several errors, which are passed through to
  2252.   DecodeXXX which in turn passes them through to its caller.  They are:
  2253.   - USER_NEXT
  2254.   - USER_EXIT
  2255.   - 0 (no error, continue decoding)
  2256.  
  2257. */
  2258.  
  2259.  
  2260. /*
  2261.  
  2262. ULONG bestmodeid(struct ScreenNode *sn,STRPTR pattern) {
  2263.   ULONG lastid=INVALID_ID;
  2264.   struct NameInfo name;
  2265.   struct DimensionInfo dimension;
  2266.   struct DisplayInfo display;
  2267.   ULONG n3;
  2268.   WORD aspect,picaspect,n,bestsize=32767,size;
  2269.   UWORD depth,n2;
  2270.   UBYTE direct,rerender,deep,gray,halvewidth;
  2271.   ULONG bestmode=~0;
  2272.  
  2273.   n2=sn->aspecty;
  2274.   if(n2==0) {
  2275.     n2=1;
  2276.   }
  2277.   n3=(ULONG)(sn->aspectx);
  2278.   n3=(n3+n3+n3)<<6;
  2279.   picaspect=n3/n2;
  2280.  
  2281.   if(arglist.debug!=0) {
  2282.     ULONG arg[4];
  2283.  
  2284.     arg[0]=sn->depth;
  2285.     arg[1]=picaspect;
  2286.     arg[2]=sn->width;
  2287.     arg[3]=sn->height;
  2288.     VPrintf("\n-- INPUT -- Depth: %2ld                    Ratio: $%04lx             (%ldx%ld)\n\n",&arg);
  2289.   }
  2290.  
  2291.   while((lastid=NextDisplayInfo(lastid))!=INVALID_ID) {
  2292.     if((GetDisplayInfoData(0,(UBYTE *)&name,sizeof(struct NameInfo),DTAG_NAME,lastid))!=0) {
  2293.       if((GetDisplayInfoData(0,(UBYTE *)&display,sizeof(struct DisplayInfo),DTAG_DISP,lastid))!=0) {
  2294.         if((GetDisplayInfoData(0,(UBYTE *)&dimension,sizeof(struct DimensionInfo),DTAG_DIMS,lastid))!=0) {
  2295.           if((arglist.screenmode==0) || (MatchPatternNoCase(pattern,name.Name)==TRUE)) {
  2296.             aspect=((display.Resolution.x)<<8)/display.Resolution.y;
  2297.             n=16384;
  2298.             while(aspect<n) {
  2299.               n>>=1;
  2300.             }
  2301.             if((aspect-n)>=(n>>1)) {
  2302.               aspect=n<<1;
  2303.             }
  2304.             else {
  2305.               aspect=n;
  2306.             }
  2307.  
  2308.             n=dimension.StdOScan.MaxX+1-sn->width;
  2309.             if(n<0) {
  2310.               n=-4*n;
  2311.             }
  2312.             size=dimension.StdOScan.MaxY+1-sn->height;
  2313.             if(size<0) {
  2314.               size=-4*size;
  2315.             }
  2316.             size+=n;
  2317.  
  2318.             depth=dimension.MaxDepth;
  2319.             direct=FALSE;
  2320.             deep=FALSE;
  2321.             gray=FALSE;
  2322.             halvewidth=FALSE;
  2323.             rerender=FALSE;
  2324.  
  2325.             if((display.PropertyFlags & DIPF_IS_FOREIGN)!=0) {
  2326.               goto rerender;
  2327.             }
  2328.             if((sn->ham==TRUE) || (sn->ehb==TRUE)) {
  2329.               if((depth==8) || ((sn->depth==6) && depth>=5)) {
  2330.                 direct=TRUE;
  2331.               }
  2332.             }
  2333.  
  2334.             rerender:
  2335.             if((depth<sn->depth) && (direct==FALSE)) {
  2336.               rerender=TRUE;
  2337.               if(((display.PropertyFlags & DIPF_IS_FOREIGN)==0) && (arglist.gray==0) && (depth>=5)) {
  2338.                 /* didn't check forced gray... */
  2339.                 /* rerendering in HAM6/8 */
  2340.                 if(aspect>picaspect) {
  2341.                   halvewidth=TRUE;
  2342.                   aspect>>=1;
  2343.                 }
  2344.               }
  2345.               else {
  2346.                 /* rerendering in GRAY4/8 */
  2347.                 gray=TRUE;
  2348.               }
  2349.               if(depth==8) {
  2350.                 deep=TRUE;
  2351.               }
  2352.             }
  2353.  
  2354.             /* all relevant info has been gathered for this screenmode, now let's
  2355.                see if it is better than our best screenmode as of yet */
  2356.  
  2357.             if(arglist.debug!=0) {
  2358.               ULONG arg[7];
  2359.  
  2360.               arg[0]=display.Header.DisplayID;
  2361.               arg[1]=display.PropertyFlags;
  2362.               arg[2]=(rerender&0x01)+((gray&0x01)<<1)+((deep&0x01)<<2)+((halvewidth&0x01)<<3)+((direct&0x01)<<4);
  2363.               arg[3]=aspect;
  2364.               arg[4]=size;
  2365.               arg[5]=dimension.StdOScan.MaxX+1;
  2366.               arg[6]=dimension.StdOScan.MaxY+1;
  2367.               VPrintf("ID: $%08lx PFlags: $%08lx Bits: $%1lx Ratio: $%04lx Size: $%04lx (%ldx%ld)\n",&arg);
  2368.             }
  2369.  
  2370.             aspect-=picaspect;
  2371.             if(aspect<0) {
  2372.               aspect=-aspect;
  2373.             }
  2374.  
  2375.             if(bestmode!=~0) {
  2376.               if(sn->rerender==FALSE) {
  2377.                 if(rerender==TRUE) {
  2378.                   goto donotusethisid;
  2379.                 }
  2380.               }
  2381.               else {
  2382.                 if(rerender==FALSE) {
  2383.                   goto usethisid;
  2384.                 }
  2385.                 if(arglist.gray!=0) {
  2386.                   /* check forced gray */
  2387.                   goto rendertypesame;
  2388.                 }
  2389.                 if(gray==TRUE) {
  2390.                   goto donotusethisid;
  2391.                 }
  2392.               }
  2393.               rendertypesame:
  2394.               if(aspect>sn->renderaspect) {
  2395.                 goto donotusethisid;
  2396.               }
  2397.               else if(aspect<sn->renderaspect) {
  2398.                 goto usethisid;
  2399.               }
  2400.               if(size>bestsize) {
  2401.                 goto donotusethisid;  /* continue ?? */
  2402.               }
  2403.             }
  2404.  
  2405.  
  2406.             usethisid:
  2407.             bestmode=display.Header.DisplayID;
  2408.             sn->renderaspect=aspect;
  2409.             sn->direct=direct;
  2410.             sn->deep=deep;
  2411.             sn->halvewidth=halvewidth;
  2412.             sn->gray=gray;
  2413.             sn->rerender=rerender;
  2414.             bestsize=size;
  2415.             sn->nominalw=dimension.StdOScan.MaxX;
  2416.             sn->nominalh=dimension.StdOScan.MaxY;
  2417.  
  2418.             donotusethisid:
  2419.           }
  2420.         }
  2421.       }
  2422.     }
  2423.   }
  2424.   return(bestmode);
  2425. }
  2426.  
  2427. */
  2428.  
  2429. /*
  2430.  
  2431. After every linedecode a getmsg routine is called which checks the user's actions.  This
  2432. routine is called from the main-decoder loop which under normal circumstances just processes
  2433. picture after picture and stores them into memory.
  2434.  
  2435. When the user wants to advance to the next picture then there are two states which we need
  2436. to take into account: A - The decoder is still decoding the current picture
  2437.                       B - The decoder is working on some other picture to be displayed later
  2438.  
  2439. These cases need different handling.  In case A the decoding routines still may still hold
  2440. buffer memory for their decoding actions, which must be freed.  In case B this is already
  2441. done.  In both cases however the main-decoder should take care of freeing the ScreenNode.
  2442.  
  2443. */
  2444.  
  2445. /*
  2446.  
  2447. AUTOSCALING
  2448.  
  2449. This feature kicks in when the screen is too large to be
  2450. opened in case of lack of (chip) memory.  In this case
  2451. FastView tries to scale down the picture (to a certain
  2452. degree) and displays the result.  When this fails as well
  2453. then FastView will return an error and continue to display
  2454. the next picture.
  2455.  
  2456.  
  2457.  
  2458. ORDER/K
  2459.  
  2460. This allows you to change the order in which the pictures
  2461. are displayed.
  2462.  
  2463.  "A" : sorts the files alphabetically by their filename
  2464.  "P" : sorts the files alphabetically by their full path name
  2465.  "R" : random
  2466.  
  2467. The default is to display the pictures in the order they
  2468. were entered on the commandline or, in the case of
  2469. wildcards, in the order they were found in the directory.
  2470. If you specify a string not beginning with one of the
  2471. letters described above then this keyword will default to
  2472. using the random order.
  2473.  
  2474. Note: Only the first letter is checked for this keyword, so it
  2475.       is possible to specify things like "ORDER=alphabetical"
  2476.       or "ORDER=random" to get the desired results.
  2477.  
  2478.  
  2479. INFO/K
  2480.  
  2481. This option displays information above the picture.  It
  2482. allows you to specify a formatting string to customize the
  2483. information.  If you specify 'INFO=""' then the default
  2484. formatting string (see below) is used.
  2485.  
  2486. To customize the information string you simply specify a
  2487. string after the keyword.  The string can contain these
  2488. special character sequences which will be automagically
  2489. replaced:
  2490.  
  2491.  %N = the complete path plus the name of the picture
  2492.  
  2493.  %n = the name of the picture (without path)
  2494.  
  2495.  %x = the horizontal size of the picture in pixels (not
  2496.       taking scaling into account)
  2497.  
  2498.  %y = the vertical size of the picture in pixels (not
  2499.       taking scaling into account)
  2500.  
  2501.  %d = the depth of the picture on disk (not the depth
  2502.       of the screen!)
  2503.  
  2504.  %% = gives you a single '%'-character
  2505.  
  2506. The default string looks like this: "%n (%xx%yx%d)" which
  2507. for example could result into:
  2508.  
  2509.  Test.jpg (640x480x24)
  2510.  
  2511. for a color JPEG picture named 'Test.jpg' of 640x480 pixels.
  2512.  
  2513.  
  2514. F1/K, F2/K, F3/K, F4/K, F5/K, F6/K, F7/K, F8/K, F9/K, F10/K
  2515.  
  2516. These options allow you to define a custom function for each
  2517. of the function keys.  The specified function will be
  2518. executed each time you press the corresponding function key.
  2519. FastView will advance to the next picture when the function
  2520. has completed.
  2521.  
  2522. Examples (also see the INFO/K option for a description of
  2523. the special '%' character sequences):
  2524.  
  2525.   F1="Copy %N PICS:Sorted/Cars/Lamborghini/"
  2526.  
  2527.   Pressing F1 will copy the picture to
  2528.   PICS:Sorted/Cars/Lamborghini - %N is automatically
  2529.   replaced by the full pathname of the picture.  Be warned
  2530.   however that the C/Copy command simply replaces any
  2531.   picture of the same name in the destination directory.
  2532.  
  2533.   F5="Rename %N :Trashcan/%n"
  2534.  
  2535.   F5 will 'move' the picture into the trashcan directory
  2536.   on the same drive.  Note that %n is replaced by just the
  2537.   name of the picture, without its path.  Note that unlike
  2538.   C/Copy, C/Rename will fail when there is already a
  2539.   picture of the same name in the destination directory.
  2540.  
  2541.   F10="Delete %N"
  2542.  
  2543.   F10 now simulates the behaviour of the Shift + Del
  2544.   function of FastView.
  2545.  
  2546. */
  2547.